home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Libraries / GUSI 1.4.1 / GUSI / GUSIDispatch.cp < prev    next >
Encoding:
Text File  |  1994-05-01  |  24.1 KB  |  1,185 lines  |  [TEXT/MPS ]

  1. /*********************************************************************
  2. Project    :    GUSI                -    Grand Unified Socket Interface
  3. File        :    GUSIDispatch.cp-    Dispatch calls to their correct recipient
  4. Author    :    Matthias Neeracher
  5. Language    :    MPW C/C++
  6.  
  7. $Log: GUSIDispatch.cp,v $
  8. Revision 1.2  1994/05/01  23:47:34  neeri
  9. Extend fflush() kludge.
  10. Define _lastbuf for MPW 3.2 compatibility.
  11.  
  12. Revision 1.1  1994/02/25  02:28:36  neeri
  13. Initial revision
  14.  
  15. Revision 0.27  1993/11/24  00:00:00  neeri
  16. Flush stdio before closing
  17.  
  18. Revision 0.26  1993/11/22  00:00:00  neeri
  19. Extend two time loser for EBADF
  20.  
  21. Revision 0.25  1993/11/12  00:00:00  neeri
  22. Two time loser workaround for flush bug
  23.  
  24. Revision 0.24  1993/06/27  00:00:00  neeri
  25. {pre,post}_select
  26.  
  27. Revision 0.23  1993/06/27  00:00:00  neeri
  28. ftruncate
  29.  
  30. Revision 0.22  1993/06/20  00:00:00  neeri
  31. Further subtleties in console handling 
  32.  
  33. Revision 0.21  1993/05/21  00:00:00  neeri
  34. Suffixes
  35.  
  36. Revision 0.20  1993/05/15  00:00:00  neeri
  37. Try to keep errno always set on error returns
  38.  
  39. Revision 0.19  1993/05/13  00:00:00  neeri
  40. Limit Search for configuration resource to application
  41.  
  42. Revision 0.18  1993/01/31  00:00:00  neeri
  43. Introducing daemons (pleased to meet you, hope you guess my name)
  44.  
  45. Revision 0.17  1993/01/17  00:00:00  neeri
  46. Be more careful about user aborts.
  47.  
  48. Revision 0.16  1993/01/03  00:00:00  neeri
  49. GUSIConfiguration
  50.  
  51. Revision 0.15  1992/11/25  00:00:00  neeri
  52. Still trying to get standard descriptors for standalone programs right. sigh.
  53.  
  54. Revision 0.14  1992/10/05  00:00:00  neeri
  55. Small fix in event dispatching
  56.  
  57. Revision 0.13  1992/09/12  00:00:00  neeri
  58. getdtablesize()
  59.  
  60. Revision 0.12  1992/08/30  00:00:00  neeri
  61. Move hasPPC to GUSIPPC.cp, AppleTalkIdentity
  62.  
  63. Revision 0.11  1992/08/05  00:00:00  neeri
  64. Change the way standard I/O channels are opened
  65.  
  66. Revision 0.10  1992/08/03  00:00:00  neeri
  67. Move Scatter/Gather to GUSIBuffer.cp
  68.  
  69. Revision 0.9  1992/07/30  00:00:00  neeri
  70. Features with initializers
  71.  
  72. Revision 0.8  1992/07/13  00:00:00  neeri
  73. hasProcessMgr
  74.  
  75. Revision 0.7  1992/06/27  00:00:00  neeri
  76. choose(), hasNewSF
  77.  
  78. Revision 0.6  1992/06/06  00:00:00  neeri
  79. Feature
  80.  
  81. Revision 0.5  1992/04/19  00:00:00  neeri
  82. C++ Rewrite
  83.  
  84. Revision 0.4  1992/04/18  00:00:00  neeri
  85. Changed read/write/send/recv dispatchers
  86.  
  87. Revision 0.3  1992/04/17  00:00:00  neeri
  88. Spin routines
  89.  
  90. Revision 0.2  1992/04/16  00:00:00  neeri
  91. User interrupt stuff
  92.  
  93. Revision 0.1  1992/03/31  00:00:00  neeri
  94. unix domain socket calls
  95.  
  96. *********************************************************************/
  97.  
  98. #include "GUSI_P.h"
  99. #include "SetJmp.h"
  100. #include "Signal.h"
  101. #include "CursorCtl.h"
  102. #include "Resources.h"
  103. #include "Events.h" 
  104. #include "Windows.h"
  105. #include "Desk.h"
  106. #include "Script.h"
  107. #include "OSEvents.h"
  108. #include "Traps.h"
  109. #include "CommResources.h"
  110. #include "CTBUtilities.h"
  111. #include "Connections.h"
  112. #include "FileTransfers.h"
  113. #include "Terminals.h"
  114. #include "EPPC.h"
  115. #include "PLStringFuncs.h"
  116.  
  117. /***************************** Globals ******************************/
  118.  
  119. const GUSIConfiguration GUSIConfig;        // Change the order of these two declarations
  120. SocketTable                    Sockets;            //     and you'll regret it (ARM §12.6.1)
  121. GUSISpinFn                     GUSISpin     = GUSIDefaultSpin;
  122. static GUSIEvtHandler *    evtHandler    = nil;
  123. static short                evtMask        = 0;
  124. static int                    errorSock    = -1;
  125. static int                    errorType    = 0;
  126. static int                    errorCount    = 0;
  127. const int                    errorMax        = 3;
  128.  
  129. Feature     hasMakeFSSpec(
  130.                 gestaltFSAttr,
  131.                 (1<<gestaltHasFSSpecCalls),
  132.                 (1<<gestaltHasFSSpecCalls));
  133. Feature     hasAlias(
  134.                 gestaltAliasMgrAttr,
  135.                 (1<<gestaltAliasMgrPresent),
  136.                 (1<<gestaltAliasMgrPresent));
  137. Feature    hasWNE(_WaitNextEvent, ToolTrap);
  138. Feature    hasNewSF(
  139.                 gestaltStandardFileAttr,
  140.                 (1<<gestaltStandardFile58),
  141.                 (1<<gestaltStandardFile58));
  142. Feature     hasProcessMgr(
  143.                 gestaltOSAttr,
  144.                 (1<<gestaltLaunchControl),
  145.                 (1<<gestaltLaunchControl));
  146. Feature hasCRM_P(
  147.                 gestaltCRMAttr,
  148.                 (1<<gestaltCRMPresent),
  149.                 (1<<gestaltCRMPresent));
  150. Feature hasCRM(hasCRM_P, InitCRM);
  151. Feature hasCTB(hasCRM, InitCTBUtilities);
  152. Feature hasStdNBP_P(
  153.                 gestaltStdNBPAttr,
  154.                 (1<<gestaltStdNBPPresent),
  155.                 (1<<gestaltStdNBPPresent));
  156. Feature hasStdNBP(hasCTB, hasStdNBP_P);
  157. Feature hasCM(hasCTB, InitCM);
  158. Feature hasFT(hasCTB, InitFT);
  159. Feature hasTM(hasCTB, InitTM);
  160. Feature hasAppleEvents(
  161.                 gestaltAppleEventsAttr,
  162.                 (1<<gestaltAppleEventsPresent),
  163.                 (1<<gestaltAppleEventsPresent));
  164. Feature hasRevisedTimeMgr(
  165.             gestaltTimeMgrVersion,
  166.             2L);
  167.  
  168. /*********************** GUSIConfiguration members ************************/
  169.  
  170. Boolean     GUSIConfiguration::firstTime = false;
  171. short        GUSIConfiguration::we;
  172.  
  173. pascal OSErr 
  174. GetOffMyCloud(AppleEvent* /*messagein*/, AppleEvent* /*reply*/, long /*refIn*/)
  175. {
  176.     return errAEEventNotHandled;
  177. }
  178.  
  179. GUSIConfiguration::GUSIConfiguration()
  180. {
  181.     typedef GUSIConfiguration **    GUSIConfHdl;
  182.     short    oldResFile = CurResFile();
  183.     
  184.     if (!firstTime)
  185.         we = oldResFile;
  186.     else
  187.         UseResFile(we);
  188.         
  189.     GUSIConfHdl config     =    GUSIConfHdl(Get1Resource('GU∑I', GUSIRsrcID));
  190.     long            confSize    =    config ? GetHandleSize(Handle(config)) : 0;
  191.     const long    stdEvt[]    =    {
  192.         kAEOpenApplication,
  193.         kAEOpenDocuments,
  194.         kAEQuitApplication,
  195.         kAEPrintDocuments
  196.     };
  197.     
  198.     if (confSize)
  199.         *this = **config;
  200.     
  201.     if (confSize < 4 || !defaultType)
  202.         defaultType    =    'TEXT';
  203.     if (confSize < 8 || !defaultCreator)
  204.         defaultCreator    =    'MPS ';
  205.     if (confSize < 9) 
  206.         autoSpin    =    1;            // do automatic spin on read/write
  207.     if (confSize < 10) {
  208.         noChdir    =    false;    // Use chdir()
  209.         accurStat=    false;    // st_nlink = # of entries + 2
  210.         tcpDaemon=    false;
  211.         udpDaemon=    false;
  212.     }
  213.     if (confSize < 14)
  214.         version = '0102';
  215.     if (version < '0120')
  216.         numSuffices = 0;
  217.     
  218.     if (!numSuffices)
  219.         suffices = nil;
  220.     else if (suffices = new GUSISuffix[numSuffices]) {
  221.         memcpy(suffices, &(*config)->numSuffices+1, numSuffices*sizeof(GUSISuffix));
  222.         for (int i=0; i<numSuffices; i++)
  223.             for (int j=0; j<4; j++)
  224.                 if (((char *) (suffices+i))[j] == ' ')
  225.                     ((char *) (suffices+i))[j] = 0;
  226.     }
  227.     
  228.     if (!firstTime) {
  229.         firstTime    =    true;
  230.         
  231.         if (!noChdir)
  232.             chdir(":");
  233.         
  234.         if (IsDaemon()) 
  235.             for (int i = 0; i < sizeof(stdEvt); i++) 
  236.                 AEInstallEventHandler(
  237.                     kCoreEventClass, 
  238.                     stdEvt[i], 
  239.                     EventHandlerProcPtr(GetOffMyCloud), 
  240.                     0, 
  241.                     false);
  242.     } else
  243.         UseResFile(oldResFile);
  244. }
  245.  
  246. void GUSIConfiguration::SetDefaultFType(const TFileSpec & name) const
  247. {
  248.     FInfo    info;    
  249.  
  250.     if (HGetFInfo(name.vRefNum, name.parID, name.name, &info))
  251.         return;
  252.  
  253.     Ptr dot = PLstrrchr(name.name, '.');
  254.     
  255.     if (dot && (name.name[0] - (dot-Ptr(name.name))) <= 4) {
  256.         char searchsuffix[5];
  257.         
  258.         strncpy(searchsuffix, dot+1, name.name[0] - (dot-Ptr(name.name)));
  259.         
  260.         for (int i = 0; i<numSuffices; i++)
  261.             if (!strncmp(suffices[i].suffix, searchsuffix, 4)) {
  262.                 info.fdType     =    suffices[i].suffType;
  263.                 info.fdCreator    =    suffices[i].suffCreator;
  264.                 
  265.                 goto determined;
  266.             }
  267.     }
  268.  
  269.     info.fdType     =    defaultType;
  270.     info.fdCreator    =    defaultCreator;
  271.  
  272. determined:    
  273.     HSetFInfo(name.vRefNum, name.parID, name.name, &info);
  274. }
  275.  
  276. inline void GUSIConfiguration::DoAutoSpin() const 
  277. {
  278.     if (autoSpin)
  279.         SAFESPIN(0, SP_AUTO_SPIN, autoSpin);
  280. }
  281.  
  282. Boolean GUSIConfiguration::IsDaemon() const
  283. {
  284.     return tcpDaemon || udpDaemon;
  285. }
  286.  
  287. /************************ External routines *************************/
  288.  
  289. int getdtablesize()
  290. {
  291.     return GUSI_MAX_FD;
  292. }
  293.  
  294. int socket(int domain, int type, int protocol)
  295. {
  296.     SocketDomain *    dom;
  297.     Socket *         sock;
  298.     int                fd;
  299.  
  300.     if (dom = SocketDomain::Domain(domain))
  301.         if (sock = dom->socket(type, protocol))
  302.             if ((fd = Sockets.Install(sock)) != -1)
  303.                 return fd;
  304.             else
  305.                 delete sock;
  306.  
  307.     if (!errno)
  308.         return GUSI_error(ENOMEM);
  309.     else
  310.         return -1;
  311. }
  312.  
  313. extern "C" int file_open(const char * name, int flags);
  314. extern Boolean IsDevice(const char * fn);
  315.  
  316. int open(const char * filename, int oflag)
  317. {
  318.     extern int     StandAlone;
  319.     static int     ignore = 3;
  320.     Socket *     sock;
  321.     int            fd;
  322.  
  323.     if (StandAlone && ignore && IsDevice(filename)) {        // Standalone programs open console manually
  324.         if (GUSIConfig.IsDaemon())
  325.             return 3 - (ignore--);
  326.             
  327.         close(3 - ignore);
  328.         
  329.         --ignore;
  330.     }
  331.  
  332.     if (sock = FileSockets.open(filename, oflag))    {
  333.         if ((fd = Sockets.Install(sock)) != -1)
  334.             return fd;
  335.         else
  336.             delete sock;
  337.     }
  338.  
  339.     if (!errno)
  340.         return GUSI_error(ENOMEM);
  341.     else
  342.         return -1;
  343. }
  344.  
  345. int choose(int domain, int type, char * prompt, void * constraint, int flags, void * name, int * namelen)
  346. {
  347.     SocketDomain *    dom;
  348.  
  349.     if (dom = SocketDomain::Domain(domain))
  350.         return dom->choose(type, prompt, constraint, flags, name, namelen);
  351.  
  352.     return -1;
  353. }
  354.  
  355. int bind(int s, const struct sockaddr *name, int namelen)
  356. {
  357.     Socket *    sock    =    Sockets[s];
  358.  
  359.     return sock ? sock->bind((void *) name, namelen) : -1;
  360. }
  361.  
  362. int connect(int s, const struct sockaddr *addr, int addrlen)
  363. {
  364.     Socket *    sock    =    Sockets[s];
  365.  
  366.     return sock ? sock->connect((void *) addr, addrlen) : -1;
  367. }
  368.  
  369. int listen(int s, int qlen)
  370. {
  371.     Socket *    sock    =    Sockets[s];
  372.  
  373.     return sock ? sock->listen(qlen) : -1;
  374. }
  375.  
  376. int accept(int s, struct sockaddr *addr, int *addrlen)
  377. {
  378.     Socket *    sock    =    Sockets[s];
  379.  
  380.     if (sock)
  381.         if (sock    = sock->accept(addr, addrlen))
  382.             if ((s = Sockets.Install(sock)) != -1)
  383.                 return s;
  384.             else
  385.                 delete sock;
  386.  
  387.     return -1;
  388. }
  389.  
  390. int close(int s)
  391. {
  392.     errorSock    =    -1;
  393.     
  394.     return Sockets.Remove(s);
  395. }
  396.  
  397. int read(int s, char *buffer, unsigned buflen)
  398. {
  399.     GUSIConfig.DoAutoSpin();
  400.     
  401.     Socket *    sock    =    Sockets[s];
  402.  
  403.     return sock ? sock->read(buffer, buflen) : -1;
  404. }
  405.  
  406. int readv(int s, const struct iovec *iov, int count)
  407. {
  408.     GUSIConfig.DoAutoSpin();
  409.     
  410.     Socket *    sock    =    Sockets[s];
  411.  
  412.     if (sock)    {
  413.         Scatterer    scatt(iov, count);
  414.  
  415.         if (scatt)
  416.             return scatt.length(sock->read(scatt.buffer(), scatt.buflen()));
  417.         else
  418.             return GUSI_error(ENOMEM);
  419.     } else
  420.         return -1;
  421. }
  422.  
  423. int recv(int s, void *buffer, int buflen, int flags)
  424. {
  425.     GUSIConfig.DoAutoSpin();
  426.     
  427.     int         fromlen     =    0;
  428.     Socket *    sock        =    Sockets[s];
  429.  
  430.     return sock ? sock->recvfrom(buffer, buflen, flags, nil, &fromlen) : -1;
  431. }
  432.  
  433. int recvfrom(int s, void *buffer, int buflen, int flags, struct sockaddr *from, int *fromlen)
  434. {
  435.     GUSIConfig.DoAutoSpin();
  436.     
  437.     Socket *    sock    =    Sockets[s];
  438.  
  439.     return sock ? sock->recvfrom(buffer, buflen, flags, from, fromlen) : -1;
  440. }
  441.  
  442. int recvmsg(int s, struct msghdr *msg, int flags)
  443. {
  444.     GUSIConfig.DoAutoSpin();
  445.     
  446.     Socket *    sock    =    Sockets[s];
  447.  
  448.     if (sock)    {
  449.         Scatterer    scatt(msg->msg_iov, msg->msg_iovlen);
  450.  
  451.         if (scatt)
  452.             return
  453.                 scatt.length(
  454.                     sock->recvfrom(
  455.                         scatt.buffer(),
  456.                         scatt.buflen(),
  457.                         flags,
  458.                         msg->msg_name,
  459.                         (int *)&msg->msg_namelen));
  460.         else
  461.             return GUSI_error(ENOMEM);
  462.     } else
  463.         return -1;
  464. }
  465.  
  466. int write(int s, const char *buffer, unsigned buflen)
  467. {
  468.     /* fflush() in the MPW stdio library doesn't take no for an answer.
  469.         Our workaround is to treat a second subsequent ESHUTDOWN or EBADF as 
  470.         an invitation to lie by pretending the write worked.
  471.     */
  472.     
  473.     int    len;
  474.     
  475.     GUSIConfig.DoAutoSpin();
  476.     
  477.     Socket *    sock    =    Sockets[s];
  478.  
  479.     if (sock && (len = sock->write((char *) buffer, buflen)) != -1)
  480.         return len;
  481.         
  482.     switch (errno) {
  483.     case EINTR:
  484.     case EWOULDBLOCK:
  485.     case EINPROGRESS:
  486.     case EALREADY:
  487.         break;
  488.     default:
  489.         if (errorSock == s && errorType == errno) {
  490.             if (++errorCount == errorMax) {
  491.                 errorSock = -1;
  492.             
  493.                 return buflen;
  494.             }
  495.         } else {
  496.             errorSock = s;
  497.             errorType = errno;
  498.             errorCount= 1;
  499.         }
  500.     }
  501.     return -1;
  502. }
  503.  
  504. int writev(int s, const struct iovec *iov, int count)
  505. {
  506.     GUSIConfig.DoAutoSpin();
  507.     
  508.     Socket *    sock    =    Sockets[s];
  509.  
  510.     if (sock)    {
  511.         Gatherer    gath(iov, count);
  512.  
  513.         if (gath)
  514.             return gath.length(sock->write(gath.buffer(), gath.buflen()));
  515.         else
  516.             return GUSI_error(ENOMEM);
  517.     } else
  518.         return -1;
  519. }
  520.  
  521. int send(int s, void *buffer, int buflen, int flags)
  522. {
  523.     GUSIConfig.DoAutoSpin();
  524.     
  525.     Socket *    sock    =    Sockets[s];
  526.  
  527.     return sock ? sock->sendto(buffer, buflen, flags, nil, 0) : -1;
  528. }
  529.  
  530. int sendto(int s, void *buffer, int buflen, int flags, const struct sockaddr *to, int tolen)
  531. {
  532.     GUSIConfig.DoAutoSpin();
  533.     
  534.     Socket *    sock    =    Sockets[s];
  535.  
  536.     return sock ? sock->sendto(buffer, buflen, flags, (void *) to, tolen) : -1;
  537. }
  538.  
  539. int sendmsg(int s, const struct msghdr *msg,int flags)
  540. {
  541.     GUSIConfig.DoAutoSpin();
  542.     
  543.     Socket *    sock    =    Sockets[s];
  544.  
  545.     if (sock)    {
  546.         Gatherer    gath(msg->msg_iov, msg->msg_iovlen);
  547.  
  548.         if (gath)
  549.             return
  550.                 gath.length(
  551.                     sock->sendto(
  552.                         gath.buffer(),
  553.                         gath.buflen(),
  554.                         flags,
  555.                         msg->msg_name,
  556.                         msg->msg_namelen));
  557.         else
  558.             return GUSI_error(ENOMEM);
  559.     } else
  560.         return -1;
  561. }
  562.  
  563. int select(int width, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
  564. {
  565.     Socket    *    sock;
  566.     long             count;
  567.     int             s;
  568.     long             starttime, waittime;
  569.     fd_set         rd, wd, ed;
  570.     Boolean        r,w,e;
  571.     Boolean *    canRead;
  572.     Boolean *    canWrite;
  573.     Boolean *    exception;
  574.  
  575.     count = 0;
  576.     FD_ZERO(&rd);
  577.     FD_ZERO(&wd);
  578.     FD_ZERO(&ed);
  579.  
  580.     if (timeout) {
  581.         waittime =  timeout->tv_sec*60 + timeout->tv_usec/16666;
  582.         starttime = TickCount();
  583.     }
  584.  
  585.     // Check files for kosherness
  586.  
  587.     for (s = 0; s < width ; ++s)
  588.         if (    (readfds && FD_ISSET(s,readfds))
  589.             ||    (writefds && FD_ISSET(s,writefds))
  590.             ||    (exceptfds && FD_ISSET(s,exceptfds))
  591.         )
  592.             if (!Sockets[s])
  593.                 return GUSI_error(EBADF);
  594.     
  595.     for (s = 0; s < width ; ++s)
  596.         if (sock = Sockets[s]) {
  597.             r = readfds && FD_ISSET(s,readfds);
  598.             w = writefds && FD_ISSET(s,writefds);
  599.             e = exceptfds && FD_ISSET(s,exceptfds);
  600.  
  601.             if (r || w || e)
  602.                 sock->pre_select(r, w, e);
  603.         }
  604.         
  605.     do {
  606.         for (s = 0; s < width ; ++s)  {
  607.             if (sock = Sockets[s]) {
  608.                 r = false;
  609.                 w = false;
  610.                 e = false;
  611.  
  612.                 canRead = (readfds && FD_ISSET(s,readfds)) ? &r : nil;
  613.                 canWrite = (writefds && FD_ISSET(s,writefds)) ? &w : nil;
  614.                 exception = (exceptfds && FD_ISSET(s,exceptfds)) ? &e : nil;
  615.  
  616.                 if (canRead || canWrite || exception)    {
  617.                     count    += sock->select(canRead, canWrite, exception);
  618.  
  619.                     if (r)
  620.                         FD_SET(s,&rd);
  621.                     if (w)
  622.                         FD_SET(s,&wd);
  623.                     if (e)
  624.                         FD_SET(s,&ed);
  625.                 }
  626.             }
  627.         }
  628.         SPIN(false, SP_SELECT, 0);
  629.     }  while(!count &&(!timeout || TickCount() - starttime < waittime));
  630.  
  631.     for (s = 0; s < width ; ++s)
  632.         if (sock = Sockets[s]) {
  633.             r = readfds && FD_ISSET(s,readfds);
  634.             w = writefds && FD_ISSET(s,writefds);
  635.             e = exceptfds && FD_ISSET(s,exceptfds);
  636.  
  637.             if (r || w || e)
  638.                 sock->post_select(r, w, e);
  639.         }
  640.         
  641.  
  642.     if (readfds)
  643.         *readfds = rd;
  644.     if (writefds)
  645.         *writefds = wd;
  646.     if (exceptfds)
  647.         *exceptfds = ed;
  648.  
  649.     return count;
  650. }
  651.  
  652. int getsockname(int s, struct sockaddr *name, int *namelen)
  653. {
  654.     Socket *    sock    =    Sockets[s];
  655.  
  656.     return sock ? sock->getsockname(name, namelen) : -1;
  657. }
  658.  
  659. int getpeername(int s, struct sockaddr *name, int *namelen)
  660. {
  661.     Socket *    sock    =    Sockets[s];
  662.  
  663.     return sock ? sock->getpeername(name, namelen) : -1;
  664. }
  665.  
  666. int shutdown(int s, int how)
  667. {
  668.     Socket *    sock    =    Sockets[s];
  669.  
  670.     return sock ? sock->shutdown(how) : -1;
  671. }
  672.  
  673. int fcntl(int s, unsigned int cmd, int arg)
  674. {
  675.     Socket *    sock    =    Sockets[s];
  676.  
  677.     if (sock)
  678.         return (cmd == F_DUPFD) ? Sockets.Install(sock, arg) : sock->fcntl(cmd, arg);
  679.     else
  680.         return -1;
  681. }
  682.  
  683. int dup(int s)
  684. {
  685.     Socket *    sock    =    Sockets[s];
  686.  
  687.     return sock ? Sockets.Install(sock) : -1;
  688. }
  689.  
  690. int dup2(int s, int s1)
  691. {
  692.     Socket *    sock    =    Sockets[s];
  693.  
  694.     if (!sock)
  695.         return -1;
  696.  
  697.     if (Sockets[s1])
  698.         Sockets.Remove(s1);
  699.  
  700.     return Sockets.Install(sock, s1);
  701. }
  702.  
  703. int ioctl(int s, unsigned int request, long *argp)
  704. {
  705.     Socket *    sock    =    Sockets[s];
  706.  
  707.     return sock ? sock->ioctl(request, argp) : -1;
  708. }
  709.  
  710. int getsockopt(int s, int level, int optname, void *optval, int * optlen)
  711. {
  712.     Socket *    sock    =    Sockets[s];
  713.  
  714.     return sock ? sock->getsockopt(level, optname, optval, optlen) : -1;
  715. }
  716.  
  717. int setsockopt(int s, int level, int optname, void *optval, int optlen)
  718. {
  719.     Socket *    sock    =    Sockets[s];
  720.  
  721.     return sock ? sock->setsockopt(level, optname, optval, optlen) : -1;
  722. }
  723.  
  724. int fstat(int s, struct stat * buf)
  725. {
  726.     Socket *    sock    =    Sockets[s];
  727.  
  728.     return sock ? sock->fstat(buf) : -1;
  729. }
  730.  
  731. long lseek(int s, long offset, int whence)
  732. {
  733.     Socket *    sock    =    Sockets[s];
  734.  
  735.     return sock ? sock->lseek(offset, whence) : -1;
  736. }
  737.  
  738. int ftruncate(int s, long offset)
  739. {
  740.     Socket *    sock    =    Sockets[s];
  741.  
  742.     return sock ? sock->ftruncate(offset) : -1;
  743. }
  744.  
  745. int isatty(int s)
  746. {
  747.     Socket *    sock    =    Sockets[s];
  748.  
  749.     return sock ? sock->isatty() : -1;
  750. }
  751.  
  752. int GUSI_error(int err)
  753. {
  754.     errno =    err;
  755.  
  756.     return -1;
  757. }
  758.  
  759. void * GUSI_error_nil(int err)
  760. {
  761.     errno =    err;
  762.  
  763.     return nil;
  764. }
  765.  
  766. void GUSISetSpin(GUSISpinFn routine)
  767. {
  768.     GUSISpin = routine;
  769. }
  770.  
  771. GUSISpinFn GUSIGetSpin()
  772. {
  773.     return GUSISpin;
  774. }
  775.  
  776. int GUSISetEvents(GUSIEvtTable table)
  777. {
  778.     short    evt;
  779.  
  780.     evtHandler    =    table;
  781.     evtMask        =    0;
  782.  
  783.     for (evt = 0; evt<16; ++evt)
  784.         if (evtHandler[evt])
  785.             evtMask    |=    1 << evt;
  786.  
  787.     return 0;
  788. }
  789.  
  790. GUSIEvtHandler * GUSIGetEvents(void)
  791. {
  792.     return evtHandler;
  793. }
  794.  
  795. /*********************** SocketDomain members ***********************/
  796.  
  797. SocketDomain *    SocketDomain::domains[GUSI_MAX_DOMAIN];
  798.  
  799. SocketDomain * SocketDomain::Domain(int domain)
  800. {
  801.     if (domain < 0 || domain >= GUSI_MAX_DOMAIN || !domains[domain])    {
  802.         GUSI_error(EINVAL);
  803.  
  804.         return nil;
  805.     } else
  806.         return domains[domain];
  807. }
  808.  
  809. SocketDomain::SocketDomain(int domain)
  810. {
  811.     if (domains[domain])    {
  812.         Str63    msg;
  813.  
  814.         sprintf((char *) msg+1, "Duplicate declaration for domain %d\n", domain);
  815.         msg[0] = strlen((char *) msg+1);
  816.  
  817.         DebugStr(msg);
  818.     }
  819.  
  820.     domains[domain]    =    this;
  821. }
  822.  
  823. SocketDomain::~SocketDomain()
  824. {
  825. }
  826.  
  827. // Default implementations of socket() and open() just returns an error
  828.  
  829. Socket * SocketDomain::open(const char *, int)
  830. {
  831.     GUSI_error(EOPNOTSUPP);
  832.  
  833.     return nil;
  834. }
  835.  
  836. Socket * SocketDomain::socket(int, short)
  837. {
  838.     GUSI_error(EOPNOTSUPP);
  839.  
  840.     return nil;
  841. }
  842.  
  843. int SocketDomain::choose(int, char *, void *, int, void *, int *)
  844. {
  845.     return GUSI_error(EOPNOTSUPP);
  846. }
  847.  
  848. void SocketDomain::DontStrip()
  849. {
  850. }
  851.  
  852. /******************** DeviceSocketDomain member ********************/
  853.  
  854. DeviceSocketDomain * DeviceSocketDomain::firstDev            =    nil;
  855. const    Socket *            DeviceSocketDomain::TryNextDevice    =    (Socket *) -1;
  856.  
  857. DeviceSocketDomain::DeviceSocketDomain(int domain)
  858.     :    SocketDomain(domain)
  859. {
  860.     nextDev    =    firstDev;
  861.     firstDev    =    this;
  862. }
  863.  
  864. /*********************** LurkSocket members ************************/
  865.  
  866. class LurkSocket : public Socket {
  867. public:
  868.     LurkSocket(int descr);
  869. };
  870.  
  871. LurkSocket::LurkSocket(int descr)
  872.     : Socket()
  873. {
  874.     lurking    =    true;
  875.     lurkDescr=    char(descr);
  876. }
  877.  
  878. /*********************** SocketTable members ************************/
  879.  
  880. SocketTable::SocketTable()
  881. {
  882.     for (int i = 0; i < 3; i++) {
  883.         if (GUSIConfig.IsDaemon())
  884.             sockets[i]    =    new LurkSocket(i);
  885.         else
  886.             sockets[i]    =     FileSockets.stdopen(i);
  887.  
  888.         ++sockets[i]->refCount;
  889.     }
  890. }
  891.  
  892. int SocketTable::Install(Socket * sock, int start)
  893. {
  894.     short    fd;
  895.  
  896.     if (start<0 || start >= GUSI_MAX_FD)
  897.         return GUSI_error(EINVAL);
  898.  
  899.     for (fd=start; fd<GUSI_MAX_FD; ++fd)
  900.         if (!sockets[fd])    {
  901.             sockets[fd] = sock;
  902.             
  903.             ++sock->refCount;
  904.  
  905.             return fd;
  906.         }
  907.  
  908.     return GUSI_error(EMFILE);
  909. }
  910.  
  911. void SocketTable::Possess(int descr, Socket * sock)
  912. {
  913.     int i;
  914.     
  915.     for (i = 0; i<GUSI_MAX_FD; ++i)
  916.         if (sockets[i]->lurking && sockets[i]->lurkDescr == descr) {
  917.             close(i);
  918.             if (sockets[i] = sock)
  919.                 ++sock->refCount;
  920.         }
  921. }
  922.  
  923. int SocketTable::Remove(int fd)
  924. {
  925.     Socket *    sock;
  926.  
  927.     if (fd<0 || fd >= GUSI_MAX_FD || !(sock = sockets[fd]))
  928.         return GUSI_error(EBADF);
  929.  
  930.     sockets[fd]     =    nil;
  931.  
  932.     if (!--sock->refCount)
  933.         delete sock;
  934.  
  935.     return 0;
  936. }
  937.  
  938. Socket * SocketTable::operator[](int fd)
  939. {
  940.     Socket * sock;
  941.  
  942. restart:
  943.     if (fd<0 || fd >= GUSI_MAX_FD || !(sock = sockets[fd]))    {
  944.         GUSI_error(EBADF);
  945.  
  946.         return nil;
  947.     } else if (sock->lurking) {
  948.         SPINP(sockets[fd]->lurking, SP_MISC, 0);
  949.         
  950.         goto restart; 
  951.     } else
  952.         return sock;
  953. }
  954.  
  955. FILE * _lastbuf = _iob + _NFILE;
  956.  
  957. SocketTable::~SocketTable()
  958. {
  959.     int i;
  960.  
  961.     // Flush & vclose stdio files (necessary to flush buffers)
  962.     // This implementation is not nice, but who cares ?
  963.     // In case you wonder, _iob is defined in <stdio.h>
  964.  
  965.     for (i = 0; _iob+i<_lastbuf; i++)
  966.         fflush(_iob+i);
  967.  
  968.     for (i = 0; _iob+i<_lastbuf; i++)
  969.         fclose(_iob+i);
  970.  
  971.     // Close all files
  972.  
  973.     for (i = 0; i<GUSI_MAX_FD; ++i)
  974.         if (sockets[i])
  975.             close(i);
  976. }
  977.  
  978. /********************** Default spin function ***********************/
  979.  
  980. /* Borrowed from tech note 263 */
  981.  
  982. #define kMaskModifiers      0xFE00         // we need the modifiers without the
  983.                                            // command key for KeyTrans
  984. #define kMaskVirtualKey     0x0000FF00     // get virtual key from event message
  985.                                            // for KeyTrans
  986. #define kUpKeyMask          0x0080
  987. #define kShiftWord          8              // we shift the virtual key to mask it
  988.                                            // into the keyCode for KeyTrans
  989. #define kMaskASCII1         0x00FF0000     // get the key out of the ASCII1 byte
  990. #define kMaskASCII2         0x000000FF     // get the key out of the ASCII2 byte
  991. #define kPeriod             0x2E           // ascii for a period
  992.  
  993. static Boolean CmdPeriod(EventRecord *theEvent)
  994. {
  995.       Boolean  fTimeToQuit;
  996.       short    keyCode;
  997.       long     virtualKey, keyInfo, lowChar, highChar, state, keyCId;
  998.       Handle   hKCHR;
  999.     Ptr         KCHRPtr;
  1000.  
  1001.     fTimeToQuit = false;
  1002.  
  1003.     if (((*theEvent).what == keyDown) || ((*theEvent).what == autoKey)) {
  1004.  
  1005.         // see if the command key is down.  If it is, find out the ASCII
  1006.         // equivalent for the accompanying key.
  1007.  
  1008.         if ((*theEvent).modifiers & cmdKey ) {
  1009.  
  1010.             virtualKey = ((*theEvent).message & kMaskVirtualKey) >> kShiftWord;
  1011.             // And out the command key and Or in the virtualKey
  1012.             keyCode    = short(((*theEvent).modifiers & kMaskModifiers) | virtualKey);
  1013.             state      = 0;
  1014.  
  1015.             hKCHR = nil;  /* set this to nil before starting */
  1016.              KCHRPtr = (Ptr)GetEnvirons(smKCHRCache);
  1017.  
  1018.             if ( !KCHRPtr ) {
  1019.                 keyCId = GetScript(short(GetEnvirons(smKeyScript)), smScriptKeys);
  1020.  
  1021.                 hKCHR   = GetResource('KCHR',short(keyCId));
  1022.                 KCHRPtr = *hKCHR;
  1023.             }
  1024.  
  1025.             if (KCHRPtr) {
  1026.                 keyInfo = KeyTrans(KCHRPtr, keyCode, &state);
  1027.                 if (hKCHR)
  1028.                     ReleaseResource(hKCHR);
  1029.             } else
  1030.                 keyInfo = (*theEvent).message;
  1031.  
  1032.             lowChar =  keyInfo &  kMaskASCII2;
  1033.             highChar = (keyInfo & kMaskASCII1) >> 16;
  1034.             if (lowChar == kPeriod || highChar == kPeriod)
  1035.                 fTimeToQuit = true;
  1036.  
  1037.         }  // end the command key is down
  1038.     }  // end key down event
  1039.  
  1040.     return( fTimeToQuit );
  1041. }
  1042.  
  1043. Boolean GUSIInterrupt()
  1044. {
  1045.     EvQElPtr        eventQ;
  1046.  
  1047.     for (eventQ = (EvQElPtr) GetEvQHdr()->qHead; eventQ; )
  1048.         if (CmdPeriod((EventRecord *) &eventQ->evtQWhat))
  1049.             return true;
  1050.         else
  1051.             eventQ = (EvQElPtr)eventQ->qLink;
  1052.     
  1053.     return false;
  1054. }
  1055.  
  1056. int GUSIDefaultSpin(spin_msg msg, long arg)
  1057. {
  1058.     static Boolean            inForeground    =    true;
  1059.     extern int                StandAlone;
  1060.     WindowPtr                win;
  1061.     EventRecord                ev;
  1062.  
  1063.     if (inForeground)
  1064.         SpinCursor(msg == SP_AUTO_SPIN ? short(arg) : 1);
  1065.  
  1066.     if (!inForeground || StandAlone)    {
  1067.         if (GUSIInterrupt())
  1068.             goto interrupt;
  1069.             
  1070.         if (hasWNE)    {
  1071.             if (WaitNextEvent(osMask|highLevelEventMask|mDownMask|evtMask, &ev, 1, nil))
  1072.                 switch (ev.what) {
  1073.                 case mouseDown:
  1074.                     if (!evtHandler || !evtHandler[mouseDown])
  1075.                         if (FindWindow(ev.where, &win) == inSysWindow)
  1076.                             SystemClick(&ev, win);
  1077.  
  1078.                     break;
  1079.                 case osEvt:
  1080.                     if (ev.message & 1)
  1081.                         inForeground    =    true;
  1082.                     else
  1083.                         inForeground    =    false;
  1084.                     break;
  1085.                 case kHighLevelEvent:
  1086.                     if (!evtHandler || !evtHandler[kHighLevelEvent])
  1087.                         if (hasAppleEvents)    // actually pretty likely, if we get HL Events
  1088.                             if (AEProcessAppleEvent(&ev))
  1089.                                 return -1;
  1090.                     break;
  1091.                 default:
  1092.                     break;
  1093.                 }
  1094.  
  1095.             if (ev.what >= 0 && ev.what < 24 && evtHandler && evtHandler[ev.what])
  1096.                 evtHandler[ev.what](&ev);
  1097.         } else {
  1098.             long     endTicks;
  1099.  
  1100.             SystemTask();
  1101.             GetNextEvent(evtMask, &ev);
  1102.  
  1103.             if (ev.what >= 0 && ev.what < 24 && evtHandler && evtHandler[ev.what])
  1104.                 evtHandler[ev.what](&ev);
  1105.  
  1106.             Delay(1, &endTicks);
  1107.         }
  1108.     }
  1109.  
  1110.     return 0;
  1111.  
  1112. interrupt:
  1113.     FlushEvents(-1, 0);
  1114.  
  1115.     return -1;
  1116. }
  1117.  
  1118. /************************** Feature members **************************/
  1119.  
  1120. Feature::Feature(short trapNum, TrapType tTyp)
  1121. {
  1122.     good =
  1123.         NGetTrapAddress(trapNum, tTyp) != NGetTrapAddress(_Unimplemented, ToolTrap);
  1124. }
  1125.  
  1126. Feature::Feature(OSType type, long value)
  1127. {
  1128.     long        attr;
  1129.  
  1130.     good = (!Gestalt(type, &attr) && (attr >= value));
  1131. }
  1132.  
  1133. Feature::Feature(OSType type, long mask, long value)
  1134. {
  1135.     long        attr;
  1136.  
  1137.     good = (!Gestalt(type, &attr) && ((attr & mask) == value));
  1138. }
  1139.  
  1140. Feature::Feature(const Feature & precondition, OSErrInitializer init)
  1141. {
  1142.     good    =    precondition && !init();
  1143. }
  1144.  
  1145. Feature::Feature(OSErrInitializer init)
  1146. {
  1147.     good    =    !init();
  1148. }
  1149.  
  1150. Feature::Feature(const Feature & precondition, voidInitializer init)
  1151. {
  1152.     if (precondition)    {
  1153.         good = true;
  1154.         init();
  1155.     } else
  1156.         good = false;
  1157. }
  1158.  
  1159. Feature::Feature(voidInitializer init)
  1160. {
  1161.     good = true;
  1162.     init();
  1163. }
  1164.  
  1165. Feature::Feature(const Feature & cond1, const Feature & cond2)
  1166. {
  1167.     good = cond1 && cond2;
  1168. }
  1169.  
  1170. OSErr AppleTalkIdentity(short & net, short & node)
  1171. {
  1172.     static short    mynet;
  1173.     static short    mynode;
  1174.     static OSErr    err = 1;
  1175.  
  1176.     if (err == 1)
  1177.         if (!(err = MPPOpen()))
  1178.             err = GetNodeAddress(&mynode, &mynet);
  1179.  
  1180.  
  1181.     net    =    mynet;
  1182.     node    =    mynode;
  1183.  
  1184.     return err;
  1185. }